#pragma once
#include <array>
#include <cstdint>
#include <initializer_list>
class CrcModbus16 {
public:
  using value_type = std::uint16_t;

  explicit CrcModbus16(value_type initial = 0xFFFF) noexcept;
  void reset() noexcept;
  value_type value() const noexcept;
  value_type finalize() const noexcept;

  void update(std::uint8_t byte) noexcept;
  void update(const std::uint8_t *data, std::size_t len) noexcept;

  template <typename Range>
  static value_type calculate(const Range &range) noexcept {
    return calculate(reinterpret_cast<const std::uint8_t *>(range.data()),
                     range.size());
  }
  static value_type calculate(const std::uint8_t *data,
                              std::size_t len) noexcept;

  value_type operator()(std::initializer_list<std::uint8_t> il) const noexcept;

private:
  static const std::array<value_type, 256> kTable;
  value_type crc_;
};